#include "../inc/CentralCache.h"
#include "../inc/PageCache.h"

#include <cassert>
#include <thread>

using namespace std;

namespace memoryPoolV2 {
static const size_t SPAN_PAGES = 8; // 每次从pageCache获取span的大小(单位：页)

void *CentralCache::fetchRange(size_t idx) {
    // 索引检查，索引大于FREE_LIST_SIZE时说明申请内存过大
    //  从系统申请
    if (idx >= FREE_LIST_SIZE)
        return nullptr;

    // 自旋锁
    while (locks_[idx].test_and_set(std::memory_order_acquire))
        this_thread::yield(); // 线程让步 避免忙等 过度消耗cpu

    void *result = nullptr;
    try {
        result = centralFreeList_[idx].load(std::memory_order_relaxed);

        if (!result) {
            // 中心缓存为空，从页获取新的内存块
            size_t size = (idx + 1) * ALIGNMENT;
            result = fetchFromPageCache(size);

            if (!result) {
                locks_[idx].clear(std::memory_order_release);
                return nullptr;
            }

            // 将获取的内存块分为小块
            char *start = static_cast<char *>(result);

            size_t blockNum = (SPAN_PAGES * PageCache::PAGE_SIZE) / size;

            if (blockNum > 1) {
                // 至少两个块才构建链表
                for (size_t i = 1; i < blockNum; i++) {
                    void *cur = start + (i - 1) * size;
                    void *next = start + i * size;
                    *reinterpret_cast<void **>(cur) = next;
                }
                *reinterpret_cast<void **>(start + (blockNum - 1) * size) = nullptr;

                // 保存result的下一节点
                void *next = *reinterpret_cast<void **>(result);

                // 将result断开链表
                *reinterpret_cast<void **>(result) = nullptr;

                centralFreeList_[idx].store(next, memory_order_release);
            }
        } else {
            // 保存result的下一节点
            void *next = *reinterpret_cast<void **>(result);

            // 将result断开链表
            *reinterpret_cast<void **>(result) = nullptr;

            centralFreeList_[idx].store(next, memory_order_release);
        }
    } catch (...) {
        locks_[idx].clear(memory_order_release);
        throw;
    }

    locks_[idx].clear(memory_order_release);
    return result;
}

void CentralCache::returnRange(void *start, size_t size, size_t index) {
    if (!start || index >= FREE_LIST_SIZE)
        return;

    while (locks_[index].test_and_set(std::memory_order_acquire)) {
        this_thread::yield();
    }

    try {
        void *end = start;
        size_t cnt = 1;
        // 找到要归还的链表的最后一个节点
        while (*reinterpret_cast<void **>(end) != nullptr && cnt < size) {
            end = *reinterpret_cast<void **>(end);
            cnt++;
        }

        void *cur = centralFreeList_[index].load(std::memory_order_relaxed);
        *reinterpret_cast<void **>(end) = cur; // 原链表头接到归还链表的尾部

        // 归还的位置为新表头
        centralFreeList_[index].store(start, std::memory_order_release);

    } catch (...) {
        locks_[index].clear(memory_order_release);
        throw;
    }

    locks_[index].clear(memory_order_release);
}

void *CentralCache::fetchFromPageCache(size_t size) {
    // 计算实际需要的页数
    size_t numPages = (size + PageCache::PAGE_SIZE - 1) / PageCache::PAGE_SIZE;

    // 根据大小决定策略
    if (size <= SPAN_PAGES * PageCache::PAGE_SIZE) {
        //<=32KB 的请求固定为8页
        return PageCache::getInstance().allocateSpan(SPAN_PAGES);
    } else {
        return PageCache::getInstance().allocateSpan(numPages);
    }
}

} // namespace memoryPoolV2